
#include "type.h"
#include "const.h"
#include "protect.h"
#include "proto.h"
#include "string.h"
#include "proc.h"
#include "global.h"

PUBLIC int kernel_main() {
    disp_str("-----\"kernel_main\" begins-----\n");

    PROCESS* p_proc = proc_table; // 进程表

    p_proc -> ldt_sel = SELECTOR_LDT_FIRST; // 设置 LDT Selector

    // 将 SELECTOR_KERNEL_CS 所指向的描述符拷贝到进程 PCB 的 LDTS[0] 处
    memcpy(&p_proc -> ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3], sizeof(DESCRIPTOR));
    p_proc -> ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5; // 设置属性，更改 DPL
    // 将 SELECTOR_KERNEL_DS 所指向的描述符拷贝到进程 PCB 的 LDTS[1] 处
    memcpy(&p_proc -> ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3], sizeof(DESCRIPTOR));
    p_proc -> ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5; // 设置属性，更改 DPL
    // Tips：右移 3 位表示去掉选择子后面的 TI 和 RPL，留下描述符索引

    // 构建选择子，选择子结构：描述符索引(15~3) TI(2) RPL(1~0)
    // LDT 共有两个描述符,分别被初始化成内核代码段和内核数据段，只是改变了一下 DPL 使其运行在低特权级下

    // CS 指向第一个描述符
    p_proc -> regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    // 其它的指向第二个描述符
    p_proc -> regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc -> regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc -> regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc -> regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    // gs 仍然指向显存，只是改变了 RPL
    p_proc -> regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | RPL_TASK;
    // TestA 这是最先开始运行的
    p_proc -> regs.eip = (u32) TestA;
    // esp 表示 TestA 这个程序运行所需的栈
    p_proc -> regs.esp = (u32) task_stack + STACK_SIZE_TOTAL;
    // 设置标志位，IF=1, IOPL=1, 第二位总是为 1
    // 设置 IOPL 后进程就可以使用 I/O 指令了
    // 并且中断会在 iretd 执行时被打开（之前在 kernel.asm 中 sti 被注释掉了，这里会自动打开）
    p_proc -> regs.eflags = 0x1202;

    p_proc_ready = proc_table;
    restart();

    while(1);
}

void TestA() {
    int i = 0;
    while(1) {
        disp_str("A");
        disp_int(i++);
        disp_str(".");
        delay(1);
    }
}


